![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@colyseus/schema
Advanced tools
A binary schema-based serialization algorithm.
Although it was born to be used on Colyseus, this library can be used as standalone.
Decoders currently available for JavaScript, LUA, C#, C++ and Haxe.
As Colyseus is written in TypeScript, the schema is defined as type annotations inside the state class. Additional server logic may be added to that class, but client-side generated (not implemented) files will consider only the schema itself.
import { Schema, type, ArraySchema, MapSchema } from '@colyseus/schema';
export class Player extends Schema {
@type("string")
name: string;
@type("number")
x: number;
@type("number")
y: number;
}
export class State extends Schema {
@type('string')
fieldString: string;
@type('number') // varint
fieldNumber: number;
@type(Player)
player: Player;
@type([ Player ])
arrayOfPlayers: ArraySchema<Player>;
@type({ map: Player })
mapOfPlayers: MapSchema<Player>;
}
See example.
Type | Description | Limitation |
---|---|---|
string | utf8 strings | maximum byte size of 4294967295 |
number | auto-detects int or float type. (extra byte on output) | 0 to 18446744073709551615 |
boolean | true or false | 0 or 1 |
int8 | signed 8-bit integer | -128 to 127 |
uint8 | unsigned 8-bit integer | 0 to 255 |
int16 | signed 16-bit integer | -32768 to 32767 |
uint16 | unsigned 16-bit integer | 0 to 65535 |
int32 | signed 32-bit integer | -2147483648 to 2147483647 |
uint32 | unsigned 32-bit integer | 0 to 4294967295 |
int64 | signed 64-bit integer | -9223372036854775808 to 9223372036854775807 |
uint64 | unsigned 64-bit integer | 0 to 18446744073709551615 |
float32 | single-precision floating-point number | -3.40282347e+38 to 3.40282347e+38 |
float64 | double-precision floating-point number | -1.7976931348623157e+308 to 1.7976931348623157e+308 |
string
, number
, boolean
, etc)@type("string")
name: string;
@type("int32")
name: number;
Schema
type@type(Player)
player: Player;
Schema
type@type([ Player ])
arrayOfPlayers: ArraySchema<Player>;
You can't mix types inside arrays.
@type([ "number" ])
arrayOfNumbers: ArraySchema<number>;
@type([ "string" ])
arrayOfStrings: ArraySchema<string>;
Schema
type@type({ map: Player })
mapOfPlayers: MapSchema<Player>;
You can't mix types inside maps.
@type({ map: "number" })
mapOfNumbers: MapSchema<number>;
@type({ map: "string" })
mapOfStrings: MapSchema<string>;
Backwards/fowards compatibility is possible by declaring new fields at the
end of existing structures, and earlier declarations to not be removed, but
be marked @deprecated()
when needed.
This is particularly useful for native-compiled targets, such as C#, C++, Haxe, etc - where the client-side can potentially not have the most up-to-date version of the schema definitions.
The Schema definitions can encode itself through Reflection
. You can have the
definition implementation in the server-side, and just send the encoded
reflection to the client-side, for example:
import { Schema, type, Reflection } from "@colyseus/schema";
class MyState extends Schema {
@type("string")
currentTurn: string;
// more definitions relating to more Schema types.
}
// send `encodedStateSchema` across the network
const encodedStateSchema = Reflection.encode(new MyState());
// instantiate `MyState` in the client-side, without having its definition:
const myState = Reflection.decode(encodedStateSchema);
On the example below, we are filtering entities which are close to the player entity.
import { Schema, type, filter } from "@colyseus/schema";
export class State extends Schema {
@filter(function(this: State, client: any, value: Entity) {
const currentPlayer = this.entities[client.sessionId]
var a = value.x - currentPlayer.x;
var b = value.y - currentPlayer.y;
return (Math.sqrt(a * a + b * b)) <= 10;
})
@type({ map: Entity })
entities = new MapSchema<Entity>();
}
NaN
or null
numbers are encoded as 0
null
strings are encoded as ""
Infinity
numbers are encoded as Number.MAX_SAFE_INTEGER
@colyseus/schema
encodes only field values in the specified order.
2
extra bytes for each index change. Example: If you have an array of 20 items, and remove the first item (through shift()
) this means 38
extra bytes to be serialized.2
extra bytes per key move.TODO: describe how changes will arrive on array and map types
import { DataChange } from "@colyseus/schema";
import { State } from "./YourStateDefinition";
const decodedState = new State();
decodedState.onChange = function(changes: DataChange[]) {
assert.equal(changes.length, 1);
assert.equal(changes[0].field, "fieldNumber");
assert.equal(changes[0].value, 50);
assert.equal(changes[0].previousValue, undefined);
}
decodedState.decode(incomingData);
If you're using JavaScript or LUA, there's no need to bother about this. Interpreted programming languages are able to re-build the Schema locally through the use of
Reflection
.
You can generate the client-side schema files based on the TypeScript schema definitions automatically.
# C#/Unity
schema-codegen ./schemas/State.ts --output ./unity-project/ --csharp
# C/C++
schema-codegen ./schemas/State.ts --output ./cpp-project/ --cpp
# Haxe
schema-codegen ./schemas/State.ts --output ./haxe-project/ --haxe
Scenario | @colyseus/schema | msgpack + fossil-delta |
---|---|---|
Initial state size (100 entities) | 2671 | 3283 |
Updating x/y of 1 entity after initial state | 9 | 26 |
Updating x/y of 50 entities after initial state | 342 | 684 |
Updating x/y of 100 entities after initial state | 668 | 1529 |
Decoders for each target language are located at /decoders/
. They have no third party dependencies.
Initial thoghts/assumptions, for Colyseus:
Practical Colyseus issues this should solve:
MIT
FAQs
Binary state serializer with delta encoding for games
The npm package @colyseus/schema receives a total of 3,001 weekly downloads. As such, @colyseus/schema popularity was classified as popular.
We found that @colyseus/schema demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.